home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magazyn Exec 5
/
CD_Magazyn_EXEC_nr_5.iso
/
eXec
/
Krotkie opisy
/
Programy
/
XADMaster
/
xad_bzip2.lha
/
bzip2.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-12-09
|
57KB
|
1,740 lines
/* This XAD client is written by Kyzer/CSG <kyzer@4u.net>, the actual
* decompression code is written by bzip2's author, Julian Seward. bzip2
* is (C) 1996-2000 Julian R. Seward. Please see some of his files for more
* information.
*
* License:
* - The modified and unmodified code of libbzip2 is (C) Julian R. Seward
* and retains its original license. However, you should not directly
* use these modified versions, you should obtain the original bzip2
* and libbzip2 from http://sourceware.cygnus.com/bzip2/
* - This contraction of the libbzip2 code and the XAD client section
* is licensed under the GNU General public license, version 2.
*/
/* bzip2, (C) 1996-2000 Julian R. Seward, is a "block-sorting file
* compressor". It uses the Burrows-Wheeler block-sorting text compression
* algorithm, with some Huffman coding on the output, and, run length encoding
* and randomisation thrown in to improve the speed efficiency of the
* compressor. The run-length encoding "is entirely irrelevant" and the
* randomisation "doesn't really need to be there". However, "compression is
* generally considerably better than that achieved by more conventional
* LZ77/LZ78-based compressors, and approaches the performance of the PPM
* family of statistical compressors."
*
* bzip2 is mainly used as a replacement for gzip in compressing UNIX tar
* archives, because it beats gzip (which uses the LZH-like deflate
* algorithim) in compression and is therefore useful for saving valuable
* bandwidth for Linux distributions and the like.
*
* The main 'problems' with bzip2 are:
* - it uses huge amounts of memory. The default compression mode is the
* maximum block size, which means that decompression requires 2.1Mb of RAM
* (preferably 3.5Mb), even for the tiniest files.
* - it can only compress and decompress single files - it doesn't store any
* file metadata whatsoever, not even a single file's name or size.
* - it has no idea how large the output data is in advance, and it can't even
* tell how big each block is in the file. It can only run through the data
* and tell you once it's decompressed how big it was.
*
* Even with these problems, the advantage in compression over gzip is enough
* to make it popular with new archive sites.
*
* The original bzip2 and libbzip2 are available from
* http://sourceware.cygnus.com/bzip2/
*/
/* bzip2 is actually just a file compressor, and doesn't even include any
* details about the file itself - perhaps this should be an XFD slave
* instead? A couple of reasons why not:
*
* 1. tar files are archives. gzip'ed tar files are archives too. 99% of
* bzip2 compressed files are tar archives. therefore, if gzip is an xad
* slave, bzip2 is an xad slave too.
*
* 2. bzip2 takes astonishing amounts of memory to unpack - it's far more a
* UNIX archive compressor than it is a realtime depacker for demos and
* games, which is the ethos of XFD compressors.
*/
/* bzip2 file format:
* - first, the header: 'BZh1' to 'BZh9'
* - the 1-9 in the header is the size of a block / 100000
*
* - next, 0 or more compressed data blocks
* - the block starts with recogdata: $314159265359 (BCD pi :)
* - then comes a 4 byte CRC-so-far
* - then the various state tables
* - then the sorted randomized huffed RLE data
*
* - a final block containing no data is always included
* - it's recog is $177245385090, however after the first block
* the data is 87.5% likely not to be byte aligned, so you probably
* won't see it in a hex editor.
* - there's a 4 byte final CRC, but for the reason mentioned above,
* it's difficult to check.
*
* - minimum size of file is 14 bytes for a 0 byte input file (just a
* header and the final block, no data blocks), or 37 bytes for a 1 byte
* input file
*
* bzip2, by virtue of early recklessness and backwards compatibility on
* the part of the author, does not contain *any* information whatsoever
* about the data itself, it can't even know how long a block is without
* decompressing it. But hey! It beats gzip on compression, so that's got
* to be good, right?
*/
/* CHANGES TO LIBBZIP2
*
* All files are collected into a single file.
* All superfluous header definitions are removed.
* All compression code and definitions are removed.
*
* The decompresser has been modified to try and enter 'small mode'
* automatically if it cannot allocate enough memory for 'fast mode'. The
* library normally expects you to say which mode you want and sticks rigidly
* to that.
*
* Assertion failures in decompression (that is, failures of the code that
* can't logically occur) are turned into returning error codes, as the XAD
* client can't support the immediate exit() that libbzip2 would like -
* instead we have to pop back to the original entry point and return, it's
* the only way.
*
* The random number table 'rNums' has been made into Int16 instead of Int32.
* This halves the size of the table (and saves exactly 1Kb), yet because all
* the numbers are small enough to fit into an Int16, it doesn't require
* changing code at all. All I've added is an explicit cast when a table entry
* is retrieved, to be on the safe side. This optimisation was suggested by
* Dirk Stöcker.
*
* The CRC table is now generated at runtime, saving another 1Kb. The code for
* this was written by Dirk Stöcker.
*/
/* VERSION HISTORY
*
* v1.0: original
* v1.1: uses XAD's new 'no size' flag and default name. Released with XAD 6.
* v1.2: now uses bzip2-1.0.0 sources.
* v1.3: uses XAD's new 'input archive filename'. Released with XAD 7.
* v1.4: generates CRC table at runtime, slightly better file extension code.
* v1.5: "trailing garbage after EOF ignored" non-error implemented. 68040
* version and install script added.
*
* $VER: bzip2.c 1.5 (09.12.2000)
*/
#include <libraries/xadmaster.h>
#include <proto/xadmaster.h>
#include <string.h>
#include <stdlib.h>
#include "SDI_compiler.h"
#define XADBASE REG(a6, struct xadMasterBase *xadMasterBase)
#ifndef XADMASTERFILE
#define bzip2_Client FirstClient
#define NEXTCLIENT 0
const UBYTE version[] = "$VER: bzip2 1.5 (09.12.2000)";
#endif
#define BZIP2_VERSION 1
#define BZIP2_REVISION 5
void BZ2_MakeCRC32R(ULONG *buf, ULONG ID) {
ULONG k;
int i, j;
for(i = 0; i < 256; i++) {
k = i << 24;
for(j=8; j--;) k = (k & 0x80000000) ? ((k << 1) ^ ID) : (k << 1);
buf[i] = k;
}
}
/*--- bzip2 code ------------------------------------------------------------*/
/*--
This file is a part of bzip2 and/or libbzip2, a program and
library for lossless, block-sorting data compression.
Copyright (C) 1996-2000 Julian R Seward. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
3. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
4. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Julian Seward, Cambridge, UK.
jseward@acm.org
bzip2/libbzip2 version 1.0 of 21 March 2000
This program is based on (at least) the work of:
Mike Burrows
David Wheeler
Peter Fenwick
Alistair Moffat
Radford Neal
Ian H. Witten
Robert Sedgewick
Jon L. Bentley
For more information on these sources, see the manual.
--*/
#define BZ_RUN 0
#define BZ_FLUSH 1
#define BZ_FINISH 2
#define BZ_OK 0
#define BZ_RUN_OK 1
#define BZ_FLUSH_OK 2
#define BZ_FINISH_OK 3
#define BZ_STREAM_END 4
#define BZ_SEQUENCE_ERROR (-1)
#define BZ_PARAM_ERROR (-2)
#define BZ_MEM_ERROR (-3)
#define BZ_DATA_ERROR (-4)
#define BZ_DATA_ERROR_MAGIC (-5)
#define BZ_IO_ERROR (-6)
#define BZ_UNEXPECTED_EOF (-7)
#define BZ_OUTBUFF_FULL (-8)
#define BZ_CONFIG_ERROR (-9)
typedef
struct {
char *next_in;
unsigned int avail_in;
unsigned int total_in_lo32;
unsigned int total_in_hi32;
char *next_out;
unsigned int avail_out;
unsigned int total_out_lo32;
unsigned int total_out_hi32;
void *state;
void *(*bzalloc)(void *,int,int);
void (*bzfree)(void *,void *);
void *opaque;
}
bz_stream;
/*-- General stuff. --*/
#define BZ_VERSION "1.0.0, 16-May-2000"
#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1)
#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp))
/*-- Constants for the back end. --*/
#define BZ_MAX_ALPHA_SIZE 258
#define BZ_MAX_CODE_LEN 23
#define BZ_RUNA 0
#define BZ_RUNB 1
#define BZ_N_GROUPS 6
#define BZ_G_SIZE 50
#define BZ_N_ITERS 4
#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE))
/*-- Stuff for randomising repetitive blocks. --*/
#define BZ_RAND_DECLS \
LONG rNToGo; \
LONG rTPos \
#define BZ_RAND_INIT_MASK \
s->rNToGo = 0; \
s->rTPos = 0 \
#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0)
#define BZ_RAND_UPD_MASK \
if (s->rNToGo == 0) { \
s->rNToGo = (LONG) BZ2_rNums[s->rTPos]; \
s->rTPos++; \
if (s->rTPos == 512) s->rTPos = 0; \
} \
s->rNToGo--;
/*-- Stuff for doing CRCs. --*/
#define BZ_INITIALISE_CRC(crcVar) \
{ \
crcVar = 0xffffffffL; \
}
#define BZ_FINALISE_CRC(crcVar) \
{ \
crcVar = ~(crcVar); \
}
#define BZ_UPDATE_CRC(crcVar,cha) \
{ \
crcVar = (crcVar << 8) ^ \
BZ2_crc32Table[(crcVar >> 24) ^ \
((UBYTE)cha)]; \
}
/*-- states for decompression. --*/
#define BZ_X_IDLE 1
#define BZ_X_OUTPUT 2
#define BZ_X_MAGIC_1 10
#define BZ_X_MAGIC_2 11
#define BZ_X_MAGIC_3 12
#define BZ_X_MAGIC_4 13
#define BZ_X_BLKHDR_1 14
#define BZ_X_BLKHDR_2 15
#define BZ_X_BLKHDR_3 16
#define BZ_X_BLKHDR_4 17
#define BZ_X_BLKHDR_5 18
#define BZ_X_BLKHDR_6 19
#define BZ_X_BCRC_1 20
#define BZ_X_BCRC_2 21
#define BZ_X_BCRC_3 22
#define BZ_X_BCRC_4 23
#define BZ_X_RANDBIT 24
#define BZ_X_ORIGPTR_1 25
#define BZ_X_ORIGPTR_2 26
#define BZ_X_ORIGPTR_3 27
#define BZ_X_MAPPING_1 28
#define BZ_X_MAPPING_2 29
#define BZ_X_SELECTOR_1 30
#define BZ_X_SELECTOR_2 31
#define BZ_X_SELECTOR_3 32
#define BZ_X_CODING_1 33
#define BZ_X_CODING_2 34
#define BZ_X_CODING_3 35
#define BZ_X_MTF_1 36
#define BZ_X_MTF_2 37
#define BZ_X_MTF_3 38
#define BZ_X_MTF_4 39
#define BZ_X_MTF_5 40
#define BZ_X_MTF_6 41
#define BZ_X_ENDHDR_2 42
#define BZ_X_ENDHDR_3 43
#define BZ_X_ENDHDR_4 44
#define BZ_X_ENDHDR_5 45
#define BZ_X_ENDHDR_6 46
#define BZ_X_CCRC_1 47
#define BZ_X_CCRC_2 48
#define BZ_X_CCRC_3 49
#define BZ_X_CCRC_4 50
/*-- Constants for the fast MTF decoder. --*/
#define MTFA_SIZE 4096
#define MTFL_SIZE 16
/*-- Structure holding all the decompression-side stuff. --*/
typedef
struct {
/* pointer back to the struct bz_stream */
bz_stream* strm;
/* state indicator for this stream */
LONG state;
/* for doing the final run-length decoding */
UBYTE state_out_ch;
LONG state_out_len;
BOOL blockRandomised;
BZ_RAND_DECLS;
/* the buffer for bit stream reading */
ULONG bsBuff;
LONG bsLive;
/* misc administratium */
LONG blockSize100k;
BOOL smallDecompress;
LONG currBlockNo;
LONG verbosity;
/* for undoing the Burrows-Wheeler transform */
LONG origPtr;
ULONG tPos;
LONG k0;
LONG unzftab[256];
LONG nblock_used;
LONG cftab[257];
LONG cftabCopy[257];
/* for undoing the Burrows-Wheeler transform (FAST) */
ULONG *tt;
/* for undoing the Burrows-Wheeler transform (SMALL) */
UWORD *ll16;
UBYTE *ll4;
/* stored and calculated CRCs */
ULONG storedBlockCRC;
ULONG storedCombinedCRC;
ULONG calculatedBlockCRC;
ULONG calculatedCombinedCRC;
/* map of bytes used in block */
LONG nInUse;
BOOL inUse[256];
BOOL inUse16[16];
UBYTE seqToUnseq[256];
/* for decoding the MTF values */
UBYTE mtfa [MTFA_SIZE];
LONG mtfbase[256 / MTFL_SIZE];
UBYTE selector [BZ_MAX_SELECTORS];
UBYTE selectorMtf[BZ_MAX_SELECTORS];
UBYTE len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
LONG limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
LONG base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
LONG perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE];
LONG minLens[BZ_N_GROUPS];
/* save area for scalars in the main decompress code */
LONG save_i;
LONG save_j;
LONG save_t;
LONG save_alphaSize;
LONG save_nGroups;
LONG save_nSelectors;
LONG save_EOB;
LONG save_groupNo;
LONG save_groupPos;
LONG save_nextSym;
LONG save_nblockMAX;
LONG save_nblock;
LONG save_es;
LONG save_N;
LONG save_curr;
LONG save_zt;
LONG save_zn;
LONG save_zvec;
LONG save_zj;
LONG save_gSel;
LONG save_gMinlen;
LONG* save_gLimit;
LONG* save_gBase;
LONG* save_gPerm;
}
DState;
/*-- Macros for decompression. --*/
#define BZ_GET_FAST(cccc) \
s->tPos = s->tt[s->tPos]; \
cccc = (UBYTE)(s->tPos & 0xff); \
s->tPos >>= 8;
#define BZ_GET_FAST_C(cccc) \
c_tPos = c_tt[c_tPos]; \
cccc = (UBYTE)(c_tPos & 0xff); \
c_tPos >>= 8;
#define SET_LL4(i,n) \
{ if (((i) & 0x1) == 0) \
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \
s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \
}
#define GET_LL4(i) \
((((ULONG)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF)
#define SET_LL(i,n) \
{ s->ll16[i] = (UWORD)(n & 0x0000ffff); \
SET_LL4(i, n >> 16); \
}
#define GET_LL(i) \
(((ULONG)s->ll16[i]) | (GET_LL4(i) << 16))
#define BZ_GET_SMALL(cccc) \
cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \
s->tPos = GET_LL(s->tPos);
ULONG BZ2_crc32Table[256];
static WORD BZ2_rNums[512] = {
619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 985, 724, 205, 454, 863,
491, 741, 242, 949, 214, 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 878, 465, 811, 169, 869,
675, 611, 697, 867, 561, 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 170, 607, 520, 932, 727,
476, 693, 425, 174, 647, 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 641, 801, 220, 162, 819,
984, 589, 513, 495, 799, 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 98, 553, 163, 354, 666,
933, 424, 341, 533, 870, 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 184, 943, 795, 384, 383,
461, 404, 758, 839, 887, 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 652, 934, 970, 447, 318,
353, 859, 672, 112, 785, 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 653, 282, 762, 623, 680,
81, 927, 626, 789, 125, 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 857, 956, 358, 619, 580,
124, 737, 594, 701, 612, 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 344, 805, 988, 739, 511,
655, 814, 334, 249, 515, 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 686, 754, 806, 760, 493,
403, 415, 394, 687, 700, 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 680, 879, 194, 572, 640,
724, 926, 56, 204, 700, 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 134, 108, 571, 364, 631,
212, 174, 643, 304, 329, 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 170, 514, 364, 692, 829,
82, 855, 953, 676, 246, 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 896, 831, 547, 261, 524,
462, 293, 465, 502, 56, 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 61, 688, 793, 644, 986,
403, 106, 366, 905, 644, 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 920, 176, 193, 713, 857,
265, 203, 50, 668, 108, 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
936, 638
};
void BZ2_hbCreateDecodeTables ( LONG *limit, LONG *base, LONG *perm,
UBYTE *length, LONG minLen, LONG maxLen, LONG alphaSize ) {
LONG pp, i, j, vec;
pp = 0;
for (i = minLen; i <= maxLen; i++)
for (j = 0; j < alphaSize; j++)
if (length[j] == i) { perm[pp] = j; pp++; };
for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
vec = 0;
for (i = minLen; i <= maxLen; i++) {
vec += (base[i+1] - base[i]);
limit[i] = vec-1;
vec <<= 1;
}
for (i = minLen + 1; i <= maxLen; i++)
base[i] = ((limit[i-1] + 1) << 1) - base[i];
}
/*---------------------------------------------------*/
static
void makeMaps_d ( DState* s )
{
LONG i;
s->nInUse = 0;
for (i = 0; i < 256; i++)
if (s->inUse[i]) {
s->seqToUnseq[s->nInUse] = i;
s->nInUse++;
}
}
/*---------------------------------------------------*/
#define RETURN(rrr) \
{ retVal = rrr; goto save_state_and_return; };
#define GET_BITS(lll,vvv,nnn) \
case lll: s->state = lll; \
while (TRUE) { \
if (s->bsLive >= nnn) { \
ULONG v; \
v = (s->bsBuff >> \
(s->bsLive-nnn)) & ((1 << nnn)-1); \
s->bsLive -= nnn; \
vvv = v; \
break; \
} \
if (s->strm->avail_in == 0) RETURN(BZ_OK); \
s->bsBuff \
= (s->bsBuff << 8) | \
((ULONG) \
(*((UBYTE*)(s->strm->next_in)))); \
s->bsLive += 8; \
s->strm->next_in++; \
s->strm->avail_in--; \
s->strm->total_in_lo32++; \
if (s->strm->total_in_lo32 == 0) \
s->strm->total_in_hi32++; \
}
#define GET_UCHAR(lll,uuu) \
GET_BITS(lll,uuu,8)
#define GET_BIT(lll,uuu) \
GET_BITS(lll,uuu,1)
/*---------------------------------------------------*/
#define GET_MTF_VAL(label1,label2,lval) \
{ \
if (groupPos == 0) { \
groupNo++; \
if (groupNo >= nSelectors) \
RETURN(BZ_DATA_ERROR); \
groupPos = BZ_G_SIZE; \
gSel = s->selector[groupNo]; \
gMinlen = s->minLens[gSel]; \
gLimit = &(s->limit[gSel][0]); \
gPerm = &(s->perm[gSel][0]); \
gBase = &(s->base[gSel][0]); \
} \
groupPos--; \
zn = gMinlen; \
GET_BITS(label1, zvec, zn); \
while (1) { \
if (zn > 20 /* the longest code */) \
RETURN(BZ_DATA_ERROR); \
if (zvec <= gLimit[zn]) break; \
zn++; \
GET_BIT(label2, zj); \
zvec = (zvec << 1) | zj; \
}; \
if (zvec - gBase[zn] < 0 \
|| zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \
RETURN(BZ_DATA_ERROR); \
lval = gPerm[zvec - gBase[zn]]; \
}
/*---------------------------------------------------*/
INLINE LONG BZ2_indexIntoF ( LONG indx, LONG *cftab )
{
LONG nb, na, mid;
nb = 0;
na = 256;
do {
mid = (nb + na) >> 1;
if (indx >= cftab[mid]) nb = mid; else na = mid;
}
while (na - nb != 1);
return nb;
}
/*---------------------------------------------------*/
LONG BZ2_decompress ( DState* s )
{
UBYTE uc;
LONG retVal;
LONG minLen, maxLen;
bz_stream* strm = s->strm;
/* stuff that needs to be saved/restored */
LONG i;
LONG j;
LONG t;
LONG alphaSize;
LONG nGroups;
LONG nSelectors;
LONG EOB;
LONG groupNo;
LONG groupPos;
LONG nextSym;
LONG nblockMAX;
LONG nblock;
LONG es;
LONG N;
LONG curr;
LONG zt;
LONG zn;
LONG zvec;
LONG zj;
LONG gSel;
LONG gMinlen;
LONG* gLimit;
LONG* gBase;
LONG* gPerm;
if (s->state == BZ_X_MAGIC_1) {
/*initialise the save area*/
s->save_i = 0;
s->save_j = 0;
s->save_t = 0;
s->save_alphaSize = 0;
s->save_nGroups = 0;
s->save_nSelectors = 0;
s->save_EOB = 0;
s->save_groupNo = 0;
s->save_groupPos = 0;
s->save_nextSym = 0;
s->save_nblockMAX = 0;
s->save_nblock = 0;
s->save_es = 0;
s->save_N = 0;
s->save_curr = 0;
s->save_zt = 0;
s->save_zn = 0;
s->save_zvec = 0;
s->save_zj = 0;
s->save_gSel = 0;
s->save_gMinlen = 0;
s->save_gLimit = NULL;
s->save_gBase = NULL;
s->save_gPerm = NULL;
}
/*restore from the save area*/
i = s->save_i;
j = s->save_j;
t = s->save_t;
alphaSize = s->save_alphaSize;
nGroups = s->save_nGroups;
nSelectors = s->save_nSelectors;
EOB = s->save_EOB;
groupNo = s->save_groupNo;
groupPos = s->save_groupPos;
nextSym = s->save_nextSym;
nblockMAX = s->save_nblockMAX;
nblock = s->save_nblock;
es = s->save_es;
N = s->save_N;
curr = s->save_curr;
zt = s->save_zt;
zn = s->save_zn;
zvec = s->save_zvec;
zj = s->save_zj;
gSel = s->save_gSel;
gMinlen = s->save_gMinlen;
gLimit = s->save_gLimit;
gBase = s->save_gBase;
gPerm = s->save_gPerm;
retVal = BZ_OK;
switch (s->state) {
GET_UCHAR(BZ_X_MAGIC_1, uc);
if (uc != 'B') RETURN(BZ_DATA_ERROR_MAGIC);
GET_UCHAR(BZ_X_MAGIC_2, uc);
if (uc != 'Z') RETURN(BZ_DATA_ERROR_MAGIC);
GET_UCHAR(BZ_X_MAGIC_3, uc)
if (uc != 'h') RETURN(BZ_DATA_ERROR_MAGIC);
GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8)
if (s->blockSize100k < '1' ||
s->blockSize100k > '9') RETURN(BZ_DATA_ERROR_MAGIC);
s->blockSize100k -= '0';
/* drops down to small mode if need be */
if (!s->smallDecompress) {
s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(LONG) );
if (s->tt == NULL) s->smallDecompress = TRUE;
}
if (s->smallDecompress) {
s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UWORD) );
s->ll4 = BZALLOC(
((1 + s->blockSize100k * 100000) >> 1) * sizeof(UBYTE)
);
if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
}
GET_UCHAR(BZ_X_BLKHDR_1, uc);
if (uc == 0x17) goto endhdr_2;
if (uc != 0x31) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_2, uc);
if (uc != 0x41) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_3, uc);
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_4, uc);
if (uc != 0x26) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_5, uc);
if (uc != 0x53) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_BLKHDR_6, uc);
if (uc != 0x59) RETURN(BZ_DATA_ERROR);
s->currBlockNo++;
s->storedBlockCRC = 0;
GET_UCHAR(BZ_X_BCRC_1, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((ULONG)uc);
GET_UCHAR(BZ_X_BCRC_2, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((ULONG)uc);
GET_UCHAR(BZ_X_BCRC_3, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((ULONG)uc);
GET_UCHAR(BZ_X_BCRC_4, uc);
s->storedBlockCRC = (s->storedBlockCRC << 8) | ((ULONG)uc);
GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
s->origPtr = 0;
GET_UCHAR(BZ_X_ORIGPTR_1, uc);
s->origPtr = (s->origPtr << 8) | ((LONG)uc);
GET_UCHAR(BZ_X_ORIGPTR_2, uc);
s->origPtr = (s->origPtr << 8) | ((LONG)uc);
GET_UCHAR(BZ_X_ORIGPTR_3, uc);
s->origPtr = (s->origPtr << 8) | ((LONG)uc);
if (s->origPtr < 0)
RETURN(BZ_DATA_ERROR);
if (s->origPtr > 10 + 100000*s->blockSize100k)
RETURN(BZ_DATA_ERROR);
/*--- Receive the mapping table ---*/
for (i = 0; i < 16; i++) {
GET_BIT(BZ_X_MAPPING_1, uc);
if (uc == 1)
s->inUse16[i] = TRUE; else
s->inUse16[i] = FALSE;
}
for (i = 0; i < 256; i++) s->inUse[i] = FALSE;
for (i = 0; i < 16; i++)
if (s->inUse16[i])
for (j = 0; j < 16; j++) {
GET_BIT(BZ_X_MAPPING_2, uc);
if (uc == 1) s->inUse[i * 16 + j] = TRUE;
}
makeMaps_d ( s );
if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
alphaSize = s->nInUse+2;
/*--- Now the selectors ---*/
GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
for (i = 0; i < nSelectors; i++) {
j = 0;
while (TRUE) {
GET_BIT(BZ_X_SELECTOR_3, uc);
if (uc == 0) break;
j++;
if (j >= nGroups) RETURN(BZ_DATA_ERROR);
}
s->selectorMtf[i] = j;
}
/*--- Undo the MTF values for the selectors. ---*/
{
UBYTE pos[BZ_N_GROUPS], tmp, v;
for (v = 0; v < nGroups; v++) pos[v] = v;
for (i = 0; i < nSelectors; i++) {
v = s->selectorMtf[i];
tmp = pos[v];
while (v > 0) { pos[v] = pos[v-1]; v--; }
pos[0] = tmp;
s->selector[i] = tmp;
}
}
/*--- Now the coding tables ---*/
for (t = 0; t < nGroups; t++) {
GET_BITS(BZ_X_CODING_1, curr, 5);
for (i = 0; i < alphaSize; i++) {
while (TRUE) {
if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
GET_BIT(BZ_X_CODING_2, uc);
if (uc == 0) break;
GET_BIT(BZ_X_CODING_3, uc);
if (uc == 0) curr++; else curr--;
}
s->len[t][i] = curr;
}
}
/*--- Create the Huffman decoding tables ---*/
for (t = 0; t < nGroups; t++) {
minLen = 32;
maxLen = 0;
for (i = 0; i < alphaSize; i++) {
if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
if (s->len[t][i] < minLen) minLen = s->len[t][i];
}
BZ2_hbCreateDecodeTables (
&(s->limit[t][0]),
&(s->base[t][0]),
&(s->perm[t][0]),
&(s->len[t][0]),
minLen, maxLen, alphaSize
);
s->minLens[t] = minLen;
}
/*--- Now the MTF values ---*/
EOB = s->nInUse+1;
nblockMAX = 100000 * s->blockSize100k;
groupNo = -1;
groupPos = 0;
for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
/*-- MTF init --*/
{
LONG ii, jj, kk;
kk = MTFA_SIZE-1;
for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
s->mtfa[kk] = (UBYTE)(ii * MTFL_SIZE + jj);
kk--;
}
s->mtfbase[ii] = kk + 1;
}
}
/*-- end MTF init --*/
nblock = 0;
GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
while (TRUE) {
if (nextSym == EOB) break;
if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
es = -1;
N = 1;
do {
if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
if (nextSym == BZ_RUNB) es = es + (1+1) * N;
N = N * 2;
GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
}
while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
es++;
uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
s->unzftab[uc] += es;
if (s->smallDecompress)
while (es > 0) {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
s->ll16[nblock] = (UWORD)uc;
nblock++;
es--;
}
else
while (es > 0) {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
s->tt[nblock] = (ULONG)uc;
nblock++;
es--;
};
continue;
} else {
if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
/*-- uc = MTF ( nextSym-1 ) --*/
{
LONG ii, jj, kk, pp, lno, off;
ULONG nn;
nn = (ULONG)(nextSym - 1);
if (nn < MTFL_SIZE) {
/* avoid general-case expense */
pp = s->mtfbase[0];
uc = s->mtfa[pp+nn];
while (nn > 3) {
LONG z = pp+nn;
s->mtfa[(z) ] = s->mtfa[(z)-1];
s->mtfa[(z)-1] = s->mtfa[(z)-2];
s->mtfa[(z)-2] = s->mtfa[(z)-3];
s->mtfa[(z)-3] = s->mtfa[(z)-4];
nn -= 4;
}
while (nn > 0) {
s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
};
s->mtfa[pp] = uc;
} else {
/* general case */
lno = nn / MTFL_SIZE;
off = nn % MTFL_SIZE;
pp = s->mtfbase[lno] + off;
uc = s->mtfa[pp];
while (pp > s->mtfbase[lno]) {
s->mtfa[pp] = s->mtfa[pp-1]; pp--;
};
s->mtfbase[lno]++;
while (lno > 0) {
s->mtfbase[lno]--;
s->mtfa[s->mtfbase[lno]]
= s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
lno--;
}
s->mtfbase[0]--;
s->mtfa[s->mtfbase[0]] = uc;
if (s->mtfbase[0] == 0) {
kk = MTFA_SIZE-1;
for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
kk--;
}
s->mtfbase[ii] = kk + 1;
}
}
}
}
/*-- end uc = MTF ( nextSym-1 ) --*/
s->unzftab[s->seqToUnseq[uc]]++;
if (s->smallDecompress)
s->ll16[nblock] = (UWORD)(s->seqToUnseq[uc]); else
s->tt[nblock] = (ULONG)(s->seqToUnseq[uc]);
nblock++;
GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
continue;
}
}
/* Now we know what nblock is, we can do a better sanity
check on s->origPtr.
*/
if (s->origPtr < 0 || s->origPtr >= nblock)
RETURN(BZ_DATA_ERROR);
s->state_out_len = 0;
s->state_out_ch = 0;
BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
s->state = BZ_X_OUTPUT;
/*-- Set up cftab to facilitate generation of T^(-1) --*/
s->cftab[0] = 0;
for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
if (s->smallDecompress) {
/*-- Make a copy of cftab, used in generation of T --*/
for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
/*-- compute the T vector --*/
for (i = 0; i < nblock; i++) {
uc = (UBYTE)(s->ll16[i]);
SET_LL(i, s->cftabCopy[uc]);
s->cftabCopy[uc]++;
}
/*-- Compute T^(-1) by pointer reversal on T --*/
i = s->origPtr;
j = GET_LL(i);
do {
LONG tmp = GET_LL(j);
SET_LL(j, i);
i = j;
j = tmp;
}
while (i != s->origPtr);
s->tPos = s->origPtr;
s->nblock_used = 0;
if (s->blockRandomised) {
BZ_RAND_INIT_MASK;
BZ_GET_SMALL(s->k0); s->nblock_used++;
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
} else {
BZ_GET_SMALL(s->k0); s->nblock_used++;
}
} else {
/*-- compute the T^(-1) vector --*/
for (i = 0; i < nblock; i++) {
uc = (UBYTE)(s->tt[i] & 0xff);
s->tt[s->cftab[uc]] |= (i << 8);
s->cftab[uc]++;
}
s->tPos = s->tt[s->origPtr] >> 8;
s->nblock_used = 0;
if (s->blockRandomised) {
BZ_RAND_INIT_MASK;
BZ_GET_FAST(s->k0); s->nblock_used++;
BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
} else {
BZ_GET_FAST(s->k0); s->nblock_used++;
}
}
RETURN(BZ_OK);
endhdr_2:
GET_UCHAR(BZ_X_ENDHDR_2, uc);
if (uc != 0x72) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_3, uc);
if (uc != 0x45) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_4, uc);
if (uc != 0x38) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_5, uc);
if (uc != 0x50) RETURN(BZ_DATA_ERROR);
GET_UCHAR(BZ_X_ENDHDR_6, uc);
if (uc != 0x90) RETURN(BZ_DATA_ERROR);
s->storedCombinedCRC = 0;
GET_UCHAR(BZ_X_CCRC_1, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((ULONG)uc);
GET_UCHAR(BZ_X_CCRC_2, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((ULONG)uc);
GET_UCHAR(BZ_X_CCRC_3, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((ULONG)uc);
GET_UCHAR(BZ_X_CCRC_4, uc);
s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((ULONG)uc);
s->state = BZ_X_IDLE;
RETURN(BZ_STREAM_END);
default: return BZ_SEQUENCE_ERROR;
}
return BZ_SEQUENCE_ERROR;
save_state_and_return:
s->save_i = i;
s->save_j = j;
s->save_t = t;
s->save_alphaSize = alphaSize;
s->save_nGroups = nGroups;
s->save_nSelectors = nSelectors;
s->save_EOB = EOB;
s->save_groupNo = groupNo;
s->save_groupPos = groupPos;
s->save_nextSym = nextSym;
s->save_nblockMAX = nblockMAX;
s->save_nblock = nblock;
s->save_es = es;
s->save_N = N;
s->save_curr = curr;
s->save_zt = zt;
s->save_zn = zn;
s->save_zvec = zvec;
s->save_zj = zj;
s->save_gSel = gSel;
s->save_gMinlen = gMinlen;
s->save_gLimit = gLimit;
s->save_gBase = gBase;
s->save_gPerm = gPerm;
return retVal;
}
/*---------------------------------------------------*/
int BZ2_bzDecompressInit(bz_stream* strm, int verbosity, int small) {
DState* s;
if (strm == NULL) return BZ_PARAM_ERROR;
if (small != 0 && small != 1) return BZ_PARAM_ERROR;
if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
s = BZALLOC( sizeof(DState) );
if (s == NULL) return BZ_MEM_ERROR;
s->strm = strm;
strm->state = s;
s->state = BZ_X_MAGIC_1;
s->bsLive = 0;
s->bsBuff = 0;
s->calculatedCombinedCRC = 0;
strm->total_in_lo32 = 0;
strm->total_in_hi32 = 0;
strm->total_out_lo32 = 0;
strm->total_out_hi32 = 0;
s->smallDecompress = (BOOL)small;
s->ll4 = NULL;
s->ll16 = NULL;
s->tt = NULL;
s->currBlockNo = 0;
s->verbosity = verbosity;
BZ2_MakeCRC32R(BZ2_crc32Table, 0x04C11DB7);
return BZ_OK;
}
/*---------------------------------------------------*/
static
void unRLE_obuf_to_output_FAST ( DState* s )
{
UBYTE k1;
if (s->blockRandomised) {
while (TRUE) {
/* try to finish existing run */
while (TRUE) {
if (s->strm->avail_out == 0) return;
if (s->state_out_len == 0) break;
*( (UBYTE*)(s->strm->next_out) ) = s->state_out_ch;
BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
s->state_out_len--;
s->strm->next_out++;
s->strm->avail_out--;
s->strm->total_out_lo32++;
if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
}
/* can a new run be started? */
if (s->nblock_used == s->save_nblock+1) return;
s->state_out_len = 1;
s->state_out_ch = s->k0;
BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
s->state_out_len = 2;
BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
s->state_out_len = 3;
BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
s->state_out_len = ((LONG)k1) + 4;
BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
}
} else {
/* restore */
ULONG c_calculatedBlockCRC = s->calculatedBlockCRC;
UBYTE c_state_out_ch = s->state_out_ch;
LONG c_state_out_len = s->state_out_len;
LONG c_nblock_used = s->nblock_used;
LONG c_k0 = s->k0;
ULONG* c_tt = s->tt;
ULONG c_tPos = s->tPos;
char* cs_next_out = s->strm->next_out;
unsigned int cs_avail_out = s->strm->avail_out;
/* end restore */
ULONG avail_out_INIT = cs_avail_out;
LONG s_save_nblockPP = s->save_nblock+1;
unsigned int total_out_lo32_old;
while (TRUE) {
/* try to finish existing run */
if (c_state_out_len > 0) {
while (TRUE) {
if (cs_avail_out == 0) goto return_notr;
if (c_state_out_len == 1) break;
*( (UBYTE*)(cs_next_out) ) = c_state_out_ch;
BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
c_state_out_len--;
cs_next_out++;
cs_avail_out--;
}
s_state_out_len_eq_one:
{
if (cs_avail_out == 0) {
c_state_out_len = 1; goto return_notr;
};
*( (UBYTE*)(cs_next_out) ) = c_state_out_ch;
BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
cs_next_out++;
cs_avail_out--;
}
}
/* can a new run be started? */
if (c_nblock_used == s_save_nblockPP) {
c_state_out_len = 0; goto return_notr;
};
c_state_out_ch = c_k0;
BZ_GET_FAST_C(k1); c_nblock_used++;
if (k1 != c_k0) {
c_k0 = k1; goto s_state_out_len_eq_one;
};
if (c_nblock_used == s_save_nblockPP)
goto s_state_out_len_eq_one;
c_state_out_len = 2;
BZ_GET_FAST_C(k1); c_nblock_used++;
if (c_nblock_used == s_save_nblockPP) continue;
if (k1 != c_k0) { c_k0 = k1; continue; };
c_state_out_len = 3;
BZ_GET_FAST_C(k1); c_nblock_used++;
if (c_nblock_used == s_save_nblockPP) continue;
if (k1 != c_k0) { c_k0 = k1; continue; };
BZ_GET_FAST_C(k1); c_nblock_used++;
c_state_out_len = ((LONG)k1) + 4;
BZ_GET_FAST_C(c_k0); c_nblock_used++;
}
return_notr:
total_out_lo32_old = s->strm->total_out_lo32;
s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
if (s->strm->total_out_lo32 < total_out_lo32_old)
s->strm->total_out_hi32++;
/* save */
s->calculatedBlockCRC = c_calculatedBlockCRC;
s->state_out_ch = c_state_out_ch;
s->state_out_len = c_state_out_len;
s->nblock_used = c_nblock_used;
s->k0 = c_k0;
s->tt = c_tt;
s->tPos = c_tPos;
s->strm->next_out = cs_next_out;
s->strm->avail_out = cs_avail_out;
/* end save */
}
}
/*---------------------------------------------------*/
static
void unRLE_obuf_to_output_SMALL ( DState* s )
{
UBYTE k1;
if (s->blockRandomised) {
while (TRUE) {
/* try to finish existing run */
while (TRUE) {
if (s->strm->avail_out == 0) return;
if (s->state_out_len == 0) break;
*( (UBYTE*)(s->strm->next_out) ) = s->state_out_ch;
BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
s->state_out_len--;
s->strm->next_out++;
s->strm->avail_out--;
s->strm->total_out_lo32++;
if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
}
/* can a new run be started? */
if (s->nblock_used == s->save_nblock+1) return;
s->state_out_len = 1;
s->state_out_ch = s->k0;
BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
s->state_out_len = 2;
BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
s->state_out_len = 3;
BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
k1 ^= BZ_RAND_MASK; s->nblock_used++;
s->state_out_len = ((LONG)k1) + 4;
BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
}
} else {
while (TRUE) {
/* try to finish existing run */
while (TRUE) {
if (s->strm->avail_out == 0) return;
if (s->state_out_len == 0) break;
*( (UBYTE*)(s->strm->next_out) ) = s->state_out_ch;
BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
s->state_out_len--;
s->strm->next_out++;
s->strm->avail_out--;
s->strm->total_out_lo32++;
if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
}
/* can a new run be started? */
if (s->nblock_used == s->save_nblock+1) return;
s->state_out_len = 1;
s->state_out_ch = s->k0;
BZ_GET_SMALL(k1); s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
s->state_out_len = 2;
BZ_GET_SMALL(k1); s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
s->state_out_len = 3;
BZ_GET_SMALL(k1); s->nblock_used++;
if (s->nblock_used == s->save_nblock+1) continue;
if (k1 != s->k0) { s->k0 = k1; continue; };
BZ_GET_SMALL(k1); s->nblock_used++;
s->state_out_len = ((LONG)k1) + 4;
BZ_GET_SMALL(s->k0); s->nblock_used++;
}
}
}
/*---------------------------------------------------*/
int BZ2_bzDecompress ( bz_stream *strm )
{
DState* s;
if (strm == NULL) return BZ_PARAM_ERROR;
s = strm->state;
if (s == NULL) return BZ_PARAM_ERROR;
if (s->strm != strm) return BZ_PARAM_ERROR;
while (TRUE) {
if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
if (s->state == BZ_X_OUTPUT) {
if (s->smallDecompress)
unRLE_obuf_to_output_SMALL ( s ); else
unRLE_obuf_to_output_FAST ( s );
if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
BZ_FINALISE_CRC ( s->calculatedBlockCRC );
if (s->calculatedBlockCRC != s->storedBlockCRC)
return BZ_DATA_ERROR;
s->calculatedCombinedCRC
= (s->calculatedCombinedCRC << 1) |
(s->calculatedCombinedCRC >> 31);
s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
s->state = BZ_X_BLKHDR_1;
} else {
return BZ_OK;
}
}
if (s->state >= BZ_X_MAGIC_1) {
LONG r = BZ2_decompress ( s );
if (r == BZ_STREAM_END) {
if (s->calculatedCombinedCRC != s->storedCombinedCRC)
return BZ_DATA_ERROR;
return r;
}
if (s->state != BZ_X_OUTPUT) return r;
}
}
return BZ_SEQUENCE_ERROR; /*NOTREACHED*/
}
/*---------------------------------------------------*/
int BZ2_bzDecompressEnd ( bz_stream *strm )
{
DState* s;
if (strm == NULL) return BZ_PARAM_ERROR;
s = strm->state;
if (s == NULL) return BZ_PARAM_ERROR;
if (s->strm != strm) return BZ_PARAM_ERROR;
if (s->tt != NULL) BZFREE(s->tt);
if (s->ll16 != NULL) BZFREE(s->ll16);
if (s->ll4 != NULL) BZFREE(s->ll4);
BZFREE(strm->state);
strm->state = NULL;
return BZ_OK;
}
/*-------------------------------------------------------------*/
/*--- end ---*/
/*-------------------------------------------------------------*/
/*--- memory functions -----------------------------------------------------*/
struct xadMasterBase *xadBase;
struct mh {
struct mh *next;
ULONG pad; /* for gcc alignment problems on 64-bit machines */
};
struct mh *initmem(XADBASE) {
struct mh *base = (struct mh *) xadAllocVec(sizeof(struct mh), 0);
xadBase = xadMasterBase;
if (base) base->next = NULL;
return base;
}
APTR allocmem(struct mh *base, ULONG size, ULONG flags) {
struct xadMasterBase *xadMasterBase = xadBase;
struct mh *mem = (struct mh *) xadAllocVec(size + sizeof(struct mh), flags);
if (!mem) return NULL;
mem->next = base->next; /* link into list */
base->next = mem;
return (APTR) ++mem;
}
void freemem(struct mh *base, APTR mem) {
struct xadMasterBase *xadMasterBase = xadBase;
struct mh *m, *x, *o;
if (!mem || !base) return;
m = (struct mh *) mem; m--; /* get correct address */
for (o = base; (x = o->next); o = x) {
if (x == m) {
o->next = x->next;
xadFreeObjectA((APTR)x, NULL);
return;
}
}
}
void freeallmem(struct mh *base) {
struct xadMasterBase *xadMasterBase = xadBase;
while (base) {
struct mh *next = base->next;
xadFreeObjectA((APTR)base, NULL);
base = next;
}
}
/*--- xad slave -------------------------------------------------------------*/
ASM(BOOL) bzip2_RecogData(REG(d0, ULONG size), REG(a0, STRPTR data), XADBASE) {
/* check file header */
if (data[0] != 'B' || data[1] != 'Z' || data[2] != 'h') return 0;
if (data[3] < '1' || data[3] > '9') return 0;
/* check first block header */
if (data[4] == 0x31) {
if (data[5] != 0x41 || data[6] != 0x59) return 0;
if (data[7] != 0x26 || data[8] != 0x53 || data[9] != 0x59) return 0;
}
else {
if (data[4] != 0x17 || data[5] != 0x72 || data[6] != 0x45) return 0;
if (data[7] != 0x38 || data[8] != 0x50 || data[9] != 0x90) return 0;
}
/* we're happy with it */
return 1;
}
/* clips .bz or .bz2, changes .tbz or .tbz2 to .tar */
void bzip2_change_ext(char *p) {
char c;
if ((c = *--p) == '2') c = *--p;
if (c == 'Z' || c == 'z') c = *--p; else return;
if (c == 'B' || c == 'b') c = *--p; else return;
if (c == '.') *p = '\0';
else if ((c == 'T' || c == 't') && p[-1] == '.') {
*p++ = 't'; *p++ = 'a'; *p++ = 'r'; *p = '\0';
}
}
ASM(LONG) bzip2_GetInfo(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
struct TagItem tags[] = {
{ XAD_OBJNAMESIZE, 0 },
{ TAG_DONE, 0 }
};
struct TagItem datetags[] = {
{ XAD_DATECURRENTTIME, 1 },
{ XAD_GETDATEXADDATE, 0 },
{ TAG_DONE, 0 }
};
/* there's only one file in a bzip archive - the uncompressed data */
struct xadFileInfo *fi;
char *name;
int namelen;
/* do we have a filename for this archive? */
if ((name = ai->xai_InName)) tags[0].ti_Data = namelen = (strlen(name) + 1);
/* allocate a fileinfo structure */
if (!(ai->xai_FileInfo = fi = (struct xadFileInfo *) xadAllocObjectA(
XADOBJ_FILEINFO, (name) ? tags : NULL))) return XADERR_NOMEMORY;
fi->xfi_Flags = XADFIF_NODATE | XADFIF_NOUNCRUNCHSIZE | XADFIF_SEEKDATAPOS;
fi->xfi_EntryNumber = 1;
fi->xfi_CrunchSize = ai->xai_InSize - 14;
fi->xfi_Size = 0;
fi->xfi_DataPos = 0;
/* fill in today's date */
datetags[1].ti_Data = (ULONG) &fi->xfi_Date;
xadConvertDatesA(datetags);
if (name) {
xadCopyMem(ai->xai_InName, (name = fi->xfi_FileName), namelen);
bzip2_change_ext(name + namelen - 1);
}
else {
fi->xfi_FileName = xadMasterBase->xmb_DefaultName;
fi->xfi_Flags |= XADFIF_NOFILENAME;
}
return XADERR_OK;
}
/* bz2lib support functions */
void *bzalloc(void *base, int a, int b) {
return allocmem((struct mh *)base, a*b, 0);
}
void bzfree(void *base, void *mem) {
freemem((struct mh *)base, mem);
}
ASM(LONG) SAVEDS bzip2_UnArchive(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
struct mh *base;
char *buf_in, *buf_out, once_ok=0;
const int bufsize = 8192;
int size;
bz_stream bzs;
LONG err, bzerr;
/* ensure we're decrunching our only file! */
if (!ai || !ai->xai_CurFile || ai->xai_CurFile->xfi_EntryNumber != 1)
return XADERR_BADPARAMS;
/* initialise memory system */
ai->xai_PrivateClient = (APTR) (base = initmem(xadMasterBase));
bzs.opaque = base;
bzs.bzalloc = bzalloc;
bzs.bzfree = bzfree;
/* allocate some buffers */
buf_in = allocmem(base, bufsize, 1);
buf_out = allocmem(base, bufsize, 1);
if (!buf_in || !buf_out) return XADERR_NOMEMORY;
/* force immediate read-in of data on first run only */
bzs.avail_in = 0;
/* always keep going - exit is only when demand passes EOF */
while (1) {
/* initialise the decompression state */
if ((bzerr=BZ2_bzDecompressInit(&bzs, 0, 0)) != BZ_OK)
return XADERR_NOMEMORY;
/* reset output buffer */
bzs.avail_out = bufsize;
bzs.next_out = buf_out;
while (bzerr == BZ_OK) {
/* fill input buffer when empty */
if (bzs.avail_in == 0) {
size = ai->xai_InSize - ai->xai_InPos;
if (size > bufsize) size = bufsize;
if (size == 0) return XADERR_OK; /** normal exit point = EOF **/
if((err = xadHookAccess(XADAC_READ, size, buf_in, ai))) return err;
bzs.next_in = buf_in;
bzs.avail_in = size;
}
/* do some more decompression */
bzerr = BZ2_bzDecompress(&bzs);
/* purge any output */
if ((size = bufsize - bzs.avail_out) > 0) {
if((err = xadHookAccess(XADAC_WRITE, size, buf_out, ai))) return err;
bzs.next_out = buf_out;
bzs.avail_out = bufsize;
}
}
switch (bzerr) {
case BZ_STREAM_END: once_ok = 1; BZ2_bzDecompressEnd(&bzs); break;
case BZ_DATA_ERROR: return XADERR_ILLEGALDATA;
case BZ_DATA_ERROR_MAGIC: return once_ok ? XADERR_OK : XADERR_ILLEGALDATA;
case BZ_MEM_ERROR: return XADERR_NOMEMORY;
default: return XADERR_DECRUNCH;
}
}
return XADERR_DECRUNCH; /* not reached! */
}
ASM(void) SAVEDS bzip2_Free(REG(a0, struct xadArchiveInfo *ai), XADBASE) {
freeallmem((struct mh *) ai->xai_PrivateClient);
ai->xai_PrivateClient = NULL;
}
const struct xadClient bzip2_Client = {
NEXTCLIENT, XADCLIENT_VERSION, 7, BZIP2_VERSION, BZIP2_REVISION,
14, /* minimum archive size */
XADCF_FILEARCHIVER | XADCF_FREEFILEINFO, /* type of client and flags */
0, /* internal ID (not needed) */
"BZip2", /* name of client */
/* client functions */
(BOOL (*)()) bzip2_RecogData,
(LONG (*)()) bzip2_GetInfo,
(LONG (*)()) bzip2_UnArchive,
(void (*)()) bzip2_Free
};